﻿using DeZhen.Core.Framework.Config;
using DeZhen.Core.Framework.Entity;
using DeZhen.Core.Redis.Entity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using StackExchange.Redis;
using StackExchange.Redis.Maintenance;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace DeZhen.Core.Redis.Service
{
    [Service(ServiceLifetime.Singleton)]
    public class RedisPlatform: IRedisPlatform
    {
        public IConnectionMultiplexer ConnectionMultiplexer { get; set; }
        public IDatabase RedisClient { get; set; }
        public RedisPlatform()
        {
            InitializeRegisterRedisConfig();
        }
        private void InitializeRegisterRedisConfig()
        {
            RedisConfig config = AppConfig.GetSection("Redis").Get<RedisConfig>();
            if (config == null)
            {
                return;
            }
            if (config.Sentinel.Enable)
            {
                List<String> ipList = config.Sentinel.Ip;
                ConfigurationOptions sentinelOptions = new ConfigurationOptions();
                foreach (var item in ipList)
                {
                    sentinelOptions.EndPoints.Add(item);
                }
                sentinelOptions.TieBreaker = "";
                sentinelOptions.CommandMap = CommandMap.Sentinel;
                sentinelOptions.AbortOnConnectFail = true;
                ConnectionMultiplexer sentinelConnection = StackExchange.Redis.ConnectionMultiplexer.Connect(sentinelOptions);
                ConfigurationOptions redisServiceOptions = new ConfigurationOptions();
                redisServiceOptions.ServiceName = config.Sentinel.ServiceName;
                redisServiceOptions.Password = config.Sentinel.Password;
                redisServiceOptions.AbortOnConnectFail = true;
                redisServiceOptions.AllowAdmin = true;
                ConnectionMultiplexer = sentinelConnection.GetSentinelMasterConnection(redisServiceOptions);
            }
            else
            {
                ConnectionMultiplexer = StackExchange.Redis.ConnectionMultiplexer.Connect(config.ConnectString);
            }
            RedisClient = ConnectionMultiplexer.GetDatabase(config.Db);
        }
        public T Get<T>(RedisKey key) where T : class
        {
            String value = RedisClient.StringGet(key);
            if (String.IsNullOrEmpty(value))
            {
                return null;
            }

            return  JsonConvert.DeserializeObject<T>(value);
        }
        public async Task<T> GetAsync<T>(RedisKey key) where T : class
        {
            String value = await RedisClient.StringGetAsync(key);
            if (String.IsNullOrEmpty(value))
            {
                return null;
            }
            return JsonConvert.DeserializeObject<T>(value);
        }
        public RedisValue StringGet(RedisKey key)
        {
            return RedisClient.StringGet(key);
        }
        public async Task<RedisValue> StringGetAsync(RedisKey key)
        {
            return await RedisClient.StringGetAsync(key);
        }
        public bool Set(RedisKey key, Object value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            if(value == null)
            {
                return false;
            }
            String valueStr = JsonConvert.SerializeObject(value);
            return RedisClient.StringSet(key, valueStr, expiry, keepTtl, when, flags);
        }
        public async Task<bool> SetAsync(RedisKey key, Object value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            if (value == null)
            {
                return false;
            }
            String valueStr = JsonConvert.SerializeObject(value);
            return await RedisClient.StringSetAsync(key, valueStr, expiry, keepTtl, when, flags);
        }
        public bool StringSet(RedisKey key, RedisValue value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None) 
        {
            return RedisClient.StringSet(key, value, expiry, keepTtl, when, flags);
        }
        public async Task<bool> StringSetAsync(RedisKey key, RedisValue value, TimeSpan? expiry = null, bool keepTtl = false, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            return await RedisClient.StringSetAsync(key, value, expiry, keepTtl, when, flags);
        }
        public bool KeyDelete(RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return RedisClient.KeyDelete(key, flags);
        }
        public long KeyDelete(RedisKey[] keys, CommandFlags flags = CommandFlags.None)
        {
            return RedisClient.KeyDelete(keys, flags);
        }
        public async Task<bool> KeyDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return await RedisClient.KeyDeleteAsync(key, flags);
        }
        public async Task<long> KeyDeleteAsync(RedisKey[] keys, CommandFlags flags = CommandFlags.None)
        {
            return await RedisClient.KeyDeleteAsync(keys, flags);
        }
        public bool KeyExists(RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return RedisClient.KeyExists(key, flags);
        }
        public async Task<bool> KeyExistsAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return await RedisClient.KeyExistsAsync(key, flags);
        }
    }
}